package com.monkeyk.os.oauth.resources;

import com.monkeyk.os.domain.oauth.AccessToken;
import com.monkeyk.os.domain.oauth.ClientDetail;
import com.monkeyk.os.domain.rs.RsOAuthClient;
import com.monkeyk.os.domain.shared.BeanProvider;
import com.monkeyk.os.service.OAuthResourceService;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.rsfilter.OAuthDecision;
import org.apache.oltu.oauth2.rsfilter.OAuthRSProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;

/**
 * 2015/7/8
 *
 * @author Shengzhao Li
 */
public class MkkOAuthRSProvider implements OAuthRSProvider {

    private static final Logger LOG = LoggerFactory.getLogger(MkkOAuthRSProvider.class);

    private transient OAuthResourceService rsService = BeanProvider.getBean(OAuthResourceService.class);

    @Override
    public OAuthDecision validateRequest(String rsId, String token, HttpServletRequest req) throws OAuthProblemException {

        LOG.debug("Call OAuthRSProvider, rsId: {},token: {},req: {}", new Object[]{rsId, token, req});

        AccessToken accessToken = rsService.loadAccessTokenByTokenId(token);

        validateToken(token, accessToken);

        ClientDetail clientDetail = rsService.loadClientDetail(accessToken.clientId(), rsId);
        validateClientDetail(token, accessToken, clientDetail);

        //TODO: It is OK?
        MkkOAuthDecision oAuthDecision = new MkkOAuthDecision().setOAuthClient(new RsOAuthClient(clientDetail));
        oAuthDecision.setPrincipal(new MkkOAuthPrincipal(accessToken.username()));
        oAuthDecision.setAuthorized(true);
        return oAuthDecision;
    }

    private void validateClientDetail(String token, AccessToken accessToken, ClientDetail clientDetail) throws OAuthProblemException {
        if (clientDetail == null || clientDetail.archived()) {
            LOG.debug("Invalid ClientDetail: {} by client_id: {}, it is null or archived", clientDetail, accessToken.clientId());
            throw OAuthProblemException.error(OAuthError.ResourceResponse.INVALID_TOKEN)
                    .description("Invalid client by token: " + token);
        }
    }

    private void validateToken(String token, AccessToken accessToken) throws OAuthProblemException {
        if (accessToken == null) {
            LOG.debug("Invalid access_token: {}, because it is null", token);
            throw OAuthProblemException.error(OAuthError.ResourceResponse.INVALID_TOKEN)
                    .description("Invalid access_token: " + token);
        }
        if (accessToken.tokenExpired()) {
            LOG.debug("Invalid access_token: {}, because it is expired", token);
            throw OAuthProblemException.error(OAuthError.ResourceResponse.EXPIRED_TOKEN)
                    .description("Expired access_token: " + token);
        }
    }
}
